Skip to content

feat(dev-preview): local browser preview for css/js with live reload - #7801

Draft
Eetwalt wants to merge 13 commits into
mainfrom
local-browser
Draft

Eetwalt wants to merge 13 commits into
mainfrom
local-browser

Conversation

@Eetwalt

@Eetwalt Eetwalt commented Jul 10, 2026

Copy link
Copy Markdown
Collaborator

Prototype to simplify the proxy setup to one npm command and no need to set up certs. With limited testing, seems to work nicely. Not that battle-tested yet, but wanted to share if you want to try it out while I'm out for the next couple of weeks!

Summary

  • Add scripts/dev-preview/ and an npm run dev command: a local MITM proxy serves your locally-built CSS/JS in place of production assets on *.liquipedia.net/commons/load.php, a file watcher rebuilds on .scss/.js save, and a dedicated browser auto-reloads — no editor integration required.
  • Node-native (http-mitm-proxy + chokidar), no Python/venv. Proxying is PAC-scoped to *.liquipedia.net and runs in a throwaway browser profile that ignores cert errors, so normal browsing is untouched.
  • Previews CSS/JS only — Lua renders server-side and still needs the dev-wiki deploy flow (noted in the README).
  • Complements the minimal mitmproxy + VSCode-task approach (feat: automate proxy setup for local testing #7391/feat: vscode task config for launching dev proxy #7799) as the batteries-included, editor-agnostic flow.
  • Docs: new "Local asset preview" section under "Testing your branch".

How did you test this change?

Limited local testing: npm run dev opens the browser with local assets, and editing .scss/.js auto-reloads the page. Not extensively battle-tested yet.

@ElectricalBoy

Copy link
Copy Markdown
Member

Few thoughts after reading OP (didn't read code):

  • Because all our deploy scripts are on Python (i.e., you'll need it for Lua dev deploy anyway), I don't think keeping the current Python-based mitmproxy dependency is a huge compromise.
  • http-mitm-proxy hasn't been updated in the last three years and seems to be abandoned at this point.
    • Could be worth looking for a more modern/maintained library replacement? idk
  • I don't think auto reload is necessarily a good thing - I use previews instead of a fully featured sandbox pages from time to time (because it is often easier to set up) and reloads may likely interfere with previews.

@ElectricalBoy ElectricalBoy added the qol Developer quality-of-life changes that are not deployed to wiki label Jul 23, 2026
Eetwalt added 12 commits August 5, 2026 14:11
http-mitm-proxy has had no release since 2023-11 and 92 open issues; the
IPv4-loopback workaround in proxy.js existed only to route around one of its
bugs. Drop it and reuse scripts/proxy_lp.py, the mitmproxy addon already on
main, so interception logic lives in one reviewed place instead of being
duplicated in classify.js.

The node side keeps everything that made this worth having: throwaway browser
profile (so no CA is installed anywhere), PAC scoping, browser detection, and
the rebuild watcher. Only the intercept moves.

proxy_lp.py absorbs classify.js's stricter matching — subdomains, an actual
/commons/load.php path check, and parsed query params rather than substring
tests on the whole URL — plus no-store and passthrough when nothing is built
yet. Its reload half stays inert unless LP_DEV_RELOAD=1, so running it
standalone injects nothing.

Reloads no longer clobber wiki previews. A css-only rebuild swaps the
stylesheet in place, and a js rebuild holds its reload back while an edit form
or unsaved textarea is live, retrying once that clears. --no-reload opts out
entirely. Rebuilds are handed over via a build-id marker file that the proxy
reads without consuming, so every open tab sees every rebuild.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new npm run dev workflow to locally preview Liquipedia CSS/JS by running a local MITM proxy + file watcher that serves locally-built load.php?only=styles|scripts assets and triggers browser reloads after rebuilds. This fits into the repo’s local development/testing tooling, complementing the existing proxy-based approaches.

Changes:

  • Add scripts/dev-preview/ Node tooling: proxy interception, request classification, PAC generation, browser launch, rebuild polling, and file watching/rebuilding.
  • Add npm run dev entry point plus required dev dependencies.
  • Document the workflow in README.md and ignore the generated .dev-preview working directory.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
scripts/dev-preview/watch.js Watches local sources and triggers CSS/JS rebuilds, flagging the proxy to reload the browser.
scripts/dev-preview/refresh-client.js Injected client snippet that polls the proxy for rebuild status and reloads the page.
scripts/dev-preview/proxy.js MITM proxy that serves local CSS/JS in place of load.php assets and exposes a rebuild-check endpoint.
scripts/dev-preview/pac.js Generates a PAC script/data URL to scope proxying to liquipedia.net domains.
scripts/dev-preview/index.js Orchestrates initial build, proxy, watcher, and launching a dedicated browser profile.
scripts/dev-preview/constants.js Central constants for paths, ports, watch globs, and browser detection candidates.
scripts/dev-preview/classify.js Classifies load.php requests into styles/scripts vs passthrough.
scripts/dev-preview/browser.js Browser binary detection and launch wrapper for the dev profile + proxy flags.
README.md Adds documentation for the local asset preview workflow and environment overrides.
package.json Adds dev script and new devDependencies needed by the preview tooling.
.gitignore Ignores the .dev-preview runtime directory created by the tool.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +35 to +59
let timer = null;
let pending = { css: false, js: false };

function schedule( kind ) {
pending[ kind ] = true;
if ( timer ) {
clearTimeout( timer );
}
timer = setTimeout( async () => {
timer = null;
const todo = pending;
pending = { css: false, js: false };
let built = false;
if ( todo.css && await runBuild( 'build:css' ) ) {
built = true;
}
if ( todo.js && await runBuild( 'build:js' ) ) {
built = true;
}
if ( built ) {
state.needsReload = true;
console.log( '[watch] rebuilt — browser will reload' );
}
}, 300 );
}
Comment thread scripts/dev-preview/browser.js Outdated
Comment on lines +21 to +22
// Thin shell: spawn the browser detached-but-tracked so we can kill it on teardown.
// --disable-quic is required: HTTP/3 bypasses the HTTP proxy entirely.
The 300ms debounce only coalesces events that arrive before the timer fires.
Once it fired, a save landing during the build started a second one: build:css
takes ~885ms, so measuring three saves 600ms apart gave overlapping runs
(START #2 at t+2384ms against END #1 at t+2730ms) with two `sass` processes
writing lua/output/css/main.css at once. The loser's bytes can end up on disk
while the marker announces a rebuild, so the browser hot-swaps to stale CSS.
writeMarker was already atomic; the asset write was not.

Builds now run single-file, and anything changed mid-build stays pending and is
picked up when the current one finishes. Same three saves produce two strictly
sequential builds instead of three overlapping ones.

Also correct the launchBrowser comment: spawn() never passed detached, and it
should not — staying in our process group is what lets Ctrl-C reach the browser,
with the explicit kill and exit handler in index.js as backup.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

qol Developer quality-of-life changes that are not deployed to wiki

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants